/*
    Video: https://www.youtube.com/watch?v=oCMOYS71NIU
    Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleNotify.cpp
    Ported to Arduino ESP32 by Evandro Copercini
   Create a BLE server that, once we receive a connection, will send periodic notifications.
   创建一个BLE服务器，一旦我们收到连接，将会周期性发送通知
   T使用步骤：
   1. 创建一个 BLE Server
   2. 创建一个 BLE Service
   3. 创建一个 BLE Characteristic
   4. 创建一个 BLE Descriptor
   5. 开始服务
   6. 开始广播
*/
#include <Arduino.h>
// #include "BluetoothSerial.h"
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>

#include <ArduinoJson.h>

#include "led.h"
#include "preferencesUtil.h"

// For led chips like WS2812, which have a data line, ground, and power, you just
// need to define DATA_PIN.  For led chipsets that are SPI based (four wires - data, clock,
// ground, and power), like the LPD8806 define both DATA_PIN and CLOCK_PIN
// Clock pin only needed for SPI based chipsets when not using hardware SPI

// BluetoothSerial SerialBT;

// ble

uint8_t txValue = 0;
BLEServer *pServer = NULL;                   // BLEServer指针 pServer
BLECharacteristic *pTxCharacteristic = NULL; // BLECharacteristic指针 pTxCharacteristic
bool deviceConnected = false;                // 本次连接状态
bool oldDeviceConnected = false;             // 上次连接状态
led_chipLet oldChiplet;
led_chipLet newChiplet;
/*
 *{chiplet:"ws2811",red:"255",blue:"255",green:"255",light:"255"}
 */

// See the following for generating UUIDs: https://www.uuidgenerator.net/
#define SERVICE_UUID "12a59900-17cc-11ec-9621-0242ac130002" // UART service UUID
#define CHARACTERISTIC_UUID_RX "12a59e0a-17cc-11ec-9621-0242ac130002"
#define CHARACTERISTIC_UUID_TX "12a5a148-17cc-11ec-9621-0242ac130002"

class MyServerCallbacks : public BLEServerCallbacks
{
  void onConnect(BLEServer *pServer)
  {
    // Serial.println("连接成功。。。");
    deviceConnected = true;
  };

  void onDisconnect(BLEServer *pServer)
  {
    // Serial.println("断开连接。。。");
    deviceConnected = false;
  }
};

class MyCallbacks : public BLECharacteristicCallbacks
{
  void onWrite(BLECharacteristic *pCharacteristic)
  {
    std::string rxValue = pCharacteristic->getValue(); // 接收信息

    if (rxValue.length() > 0)
    { // 向串口输出收到的值
      //  log_i(rxValue.c_str());
      DynamicJsonDocument doc(rxValue.length() * 2);
      // Deserialize the JSON document
      // DeserializationError error =
      deserializeJson(doc, rxValue);
      // if (error)
      // {
      //   Serial.printf("json parse error: %s", error.c_str());
      // }

      uint8_t redset = 255;   // 红色设置
      uint8_t blueset = 255;  // 蓝色设置
      uint8_t greenset = 255; // 绿色设置
      uint8_t lightset = 255; // 亮度设置
      String colorData = "{}";
      led_chipLet chiplet = WS2811;
      led_mode ledMode = LEDNORMAL;
      int pixels = 5;

      redset = doc["red"].as<uint8_t>();
      blueset = doc["blue"].as<uint8_t>();
      greenset = doc["green"].as<uint8_t>();
      lightset = doc["light"].as<uint8_t>();
      colorData = doc["colorData"].as<String>();
      chiplet = doc["chiplet"].as<led_chipLet>();
      ledMode = doc["ae"].as<led_mode>();
      pixels = doc["pixels"].as<int>();
      log_i("%s\n", colorData.c_str());
      PreferencesUtil preferenUitl;
      preferenUitl.setRedData(redset);
      preferenUitl.setGreenData(greenset);
      preferenUitl.setBlueData(blueset);
      preferenUitl.setLightData(lightset);
      preferenUitl.setColorData(colorData);
      preferenUitl.setChipLet(chiplet);
      preferenUitl.setLedMode(ledMode);
      preferenUitl.setLedPixels(pixels);

      // ws2811testLights(CRGB(redset, blueset, greenset), 3, 2);

      // for (int i = 0; i < rxValue.length(); i++)
      //   Serial.print(rxValue[i]);
      // Serial.println();
    }
  }
};
static void IRAM_ATTR rmtColor(void *parmater)
{

  while (1)
  {

    // testhigh();
    // testlow();
    PreferencesUtil preferenUitl;

    uint8_t redset = 0;   // 红色设置
    uint8_t blueset = 0;  // 蓝色设置
    uint8_t greenset = 0; // 绿色设置
    uint8_t lightset = 0; // 亮度设置

    redset = preferenUitl.getRedData();
    blueset = preferenUitl.getBlueData();
    greenset = preferenUitl.getGreenData();
    lightset = preferenUitl.getLightData();
    led_chipLet ledchipLet = preferenUitl.getChipLet();
    led_mode ledmode = preferenUitl.getLedMode();
    int pixels = preferenUitl.getLedPixels();
    String colorData = preferenUitl.getColorData();

    // deviceConnected 已连接
    if (deviceConnected)
    {

      log_i("已连接...");
      // Serial.println("已连接...");
      // Serial.println(txValue);
      ESP_LOG_BUFFER_CHAR("ble", txValue + "", sizeof(txValue));

      if (txValue <= 3)
      {
        int datalength = colorData.length() * 2;

        StaticJsonDocument<2048> doc;

        doc["red"] = redset;
        doc["blue"] = blueset;
        doc["green"] = greenset;
        doc["light"] = lightset;
        doc["ae"] = ledmode;
        doc["pixels"] = pixels;
        doc["chiplet"] = ledchipLet;
        // Serial.println(colorData);

        DynamicJsonDocument colorDataDoc(datalength);
        deserializeJson(colorDataDoc, colorData);
        doc["colorData"] = colorDataDoc;
        char buffer[2048];
        size_t dataSize = serializeJson(doc, buffer);
        Serial.println(buffer);

        pTxCharacteristic->setValue(buffer); // 设置要发送的值为1
        pTxCharacteristic->notify();         // 广播
                                             // 指针地址自加1
        txValue++;
      }

      delay(2000); // 如果有太多包要发送，蓝牙会堵塞
    }

    // disconnecting  断开连接
    if (!deviceConnected && oldDeviceConnected)
    {
      delay(500);                  // 留时间给蓝牙缓冲
      pServer->startAdvertising(); // 重新广播

      log_i("开始广播...\n");
      // ESP_LOG_BUFFER_CHAR("ble", bleMsg.c_str(), sizeof(bleMsg));
      oldDeviceConnected = deviceConnected;
      txValue = 0;
    }

    // connecting  正在连接
    if (deviceConnected && !oldDeviceConnected)
    {
      // Serial.println("正在连接...");
      log_i("正在连接...\n");
      // ESP_LOG_BUFFER_CHAR("ble", bleMsg.c_str(), sizeof(bleMsg));
      // do stuff here on connecting
      oldDeviceConnected = deviceConnected;
    }
    delay(1);
  }
  // vTaskDelete(NULL);
  
}

void setup()
{

  Serial.begin(115200);
  // tm1914_init();

  // 创建一个 BLE 设备
  BLEDevice::init("hytestESp32");

  // 创建一个 BLE 服务
  pServer = BLEDevice::createServer();
  pServer->setCallbacks(new MyServerCallbacks()); // 设置回调
  BLEService *pService = pServer->createService(SERVICE_UUID);

  // 创建一个 BLE 特征
  pTxCharacteristic = pService->createCharacteristic(CHARACTERISTIC_UUID_TX, BLECharacteristic::PROPERTY_NOTIFY);
  pTxCharacteristic->addDescriptor(new BLE2902());
  BLECharacteristic *pRxCharacteristic = pService->createCharacteristic(CHARACTERISTIC_UUID_RX, BLECharacteristic::PROPERTY_WRITE);
  pRxCharacteristic->setCallbacks(new MyCallbacks()); // 设置回调

  pService->start();                  // 开始服务
  pServer->getAdvertising()->start(); // 开始广播
  // String bleMsg = ;
  log_i("等待一个客户端连接，且发送通知...\n ");

  PreferencesUtil preferenUitl;
  oldChiplet = preferenUitl.getChipLet();

  xTaskCreate(rmtColor, "rmtColor", 204800, NULL, 1, NULL);
}

void loop()
{
  uint8_t redset = 0;   // 红色设置
  uint8_t blueset = 0;  // 蓝色设置
  uint8_t greenset = 0; // 绿色设置
  uint8_t lightset = 0; // 亮度设置

  PreferencesUtil preferenUitl;

  redset = preferenUitl.getRedData();
  blueset = preferenUitl.getBlueData();
  greenset = preferenUitl.getGreenData();
  lightset = preferenUitl.getLightData();
  String colorData = preferenUitl.getColorData();
  newChiplet = preferenUitl.getChipLet();
  led_mode led_mode = preferenUitl.getLedMode();

  // if (newChiplet != oldChiplet)
  // {
  //   Serial.println("芯片选择已经改变");
  //   oldChiplet = newChiplet;

  //   // ledInit(newChiplet);
  // delay(500);
  // }
  HYled hyled(newChiplet, preferenUitl.getLedPixels());
  // ledInit(newChiplet);
  // hyled.setLedPixels(preferenUitl.getLedPixels());
  hyled.setLedMode(preferenUitl.getLedMode(), lightset, redset, greenset, blueset);

  // FastLED.clear();
  delay(1);
}